之前在使用 SVG 开发一个条形图的过程中,我们发现有一些地方不方便。比如我们每次绘制一个元素,都需要三步:创建元素,设置元素属性,最后再挂载元素。
// 创建元素
const rect = createSVGElement('rect');
// 设置属性
rect.setAttribute('x', 10);
rect.setAttribute('y', 10);
rect.setAttribute('fill', 'red');
rect.setAttribute('width', 50);
rect.setAttribute('height', 50);
// 挂载元素
g.appendChild('rect');
当画布中元素较少时,这种方式还可以忍受。但随着元素数量的增长,这会变得非常冗余和繁琐。所以我们需要开发一个非常简单和轻量级的渲染引擎(Renderer) ,用它简化我们绘图的流程。

通过上图可以发现:Sparrow 将选择 SVG 而不是 Canvas2D 来作为绘图技术,这是因为 Sparrow 对性能没有要求,同时 SVG 相对于 Canvas2D 更好测试一点(SVG 有 DOM 结构,可以直接检查 DOM 来进行调试)。
接下来我们先从什么是渲染引擎讲起以及可视化需要它的原因,然后实现一个简单的渲染引擎,最后会简单拓展一下开源社区一些优秀的渲染引擎。
# 什么是渲染引擎
渲染引擎这一概念在不同领域有着不同的含义。对于前端开发者来数,渲染引擎是 WebKit、Blink 这样的浏览器排版引擎(或者说是内核),它负责解析 HTML 和 CSS 文档,并决定了文档里的元素将以怎样的形式放置在页面中的什么位置(即排版)。
对于艺术和计算机动画工作者来说,渲染引擎是基础图形绘制库,一般具有以下特点:
- 能够绘制基本图形,如:点、直线、多边形、曲线等
- 支持图形内部填充、阴影效果等
- 支持纹理与贴图
- 抗锯齿以及亚像素优化
- 跨平台运行
更高阶的渲染引擎甚至支持粒子系统、光线追踪等效果。
在数据可视化与可视分析领域,尤其是前端可视化方向,我们所使用的渲染引擎更偏向后者,但又有所区别。受平台及场景制约,前端可视化渲染引擎在具备上述特点的同时,还需要具备高性能、轻量化的特性,以满足在低网络传输带宽、低绘制性能等极端场景下的图形渲染需求。此外,在面向分析的可视化领域,3D 视图可能会导致意料之外的错误感知与洞察,因此 2D 渲染引擎得到了更大规模的应用。
# 为什么需要渲染引擎
用户大可直接在浏览器提供的 Canvas2D, SVG 和 WebGL 中使用原生语法直接绘制想要的图形,那么为什么还需要渲染引擎呢?包括上面提到的,这里给出几点原因:
- 管理图元:使用渲染引擎能够更轻松的绘制并管理图形元素。
- 提供完善的动画与事件机制:原声语法绘制动画相对比较麻烦。
- 性能优化:渲染引擎基于底层渲染器的特性进行了大量优化工作,如脏矩阵渲染、分层渲染等,能够取得更好的渲染性能。使得开发者能够专注于视图的构建。
- 多个渲染器之间任意切换:如果有同时在这两种渲染器中进行绘制的需求,需要针对不同的渲染器进行单独开发,提高工作量的同时也难以保证其一致性。使用渲染引擎绘制时只需要指定所需的渲染器即可完成切换。
现在我们从概念上简单聊了一下渲染引擎,就像我们一直强调的:具体的实战能帮助我们更好的理解概念,所以接下来我们就来开发 Sparrow 需要的渲染引擎。
# 功能设计
每一次开发都伴随着功能设计,它是我们接下来开发时候依据的蓝图。
因为 Sparrow 的功能相对简单,所以我们渲染器的功能用不复杂,主要侧重于更加轻松地绘制并且管理图形元素,简化我们绘制图形的流程。它主要有两个功能:
- 绘制基本图形:支持
rect、circle、line、path、text、ring这几种基本图形的绘制。 - 进行坐标系变换:支持
translate,scale,rotate这三种变换,同时可以使用类似
